﻿#pragma once

#include <map>
#include <memory>
#include <stdexcept>
#include <utility>

namespace xi
{

namespace utils
{

/**
 * @brief 通用工厂类，用于创建对象
 *
 * @tparam AbstractProduct 对象类型
 * @tparam IdType ID 类型
 * @tparam ProductCreator 构造函数类型
 */
template <class AbstractProduct, typename IdType, typename ProductCreator> class GenericFactory
{
  private:
    using CallbackMap = std::map<IdType, ProductCreator>;

  public:
    GenericFactory() = default;
    GenericFactory(GenericFactory &&) = delete;

    /**
     * @brief 根据 id 注册创建函数，返回创建是否成功
     *
     * @param[in] Id
     * @param[in] createFn
     * @return true
     * @return false
     */
    bool register_product(IdType Id, ProductCreator createFn)
    {
        return m_callbacks.insert(typename CallbackMap::value_type(Id, createFn)).second;
    }

    /**
     * @brief 销毁函数，返回是否存在该 id
     *
     * @param[in] Id
     * @return true
     * @return false
     */
    bool unregister_product(IdType Id)
    {
        return m_callbacks.erase(Id) == 1;
    }

    /**
     * @brief 根据 id 创建对象的智能指针
     *
     * @tparam TS
     * @param[in] Id
     * @param[in] args
     * @return AbstractProduct *
     */
    template <class... TS> AbstractProduct *create_product(IdType Id, TS &&...args)
    {
        auto it = m_callbacks.find(Id);
        if (it == m_callbacks.end())
            throw std::runtime_error("Unknown product ID.");

        // 可变参数调用返回智能指针，使用 forward 转发参数
        return (it->second)(std::forward<TS>(args)...);
    }

  private:
    CallbackMap m_callbacks;
};

} // namespace utils

} // namespace xi
